//
// Created by Sammar on 2024/9/30.
//

#include "ColorAntiPen.h"
/**
 * 初始化画笔的必要参数，若无初始化，则会使用默认值，效果不如预期
 * @param idevpixratio  设备像素比，正确的设备像素比才能抗锯齿
 * @param iradius。     反色圈半径
 * @param qrimagescale  图片窗口缩放比例
 */
void ColorAntiPen::initAntiColorPen(int idevpixratio, int iradius, qreal qrimagescale)
{
    mdevicpixratio = idevpixratio;
    mradius = iradius;
    mimagescale = qrimagescale;
}

/**
 * 绘制反色圈画笔
 * @param sourceimg 原图
 * @param circenterpoint 原点
 * @param rectpos 反色圈图片位置
 * @param outimg  反色圈图片
 * @return
 */
int ColorAntiPen::drawAntiCirclePen(QImage sourceimg, QPointF circenterpoint, QRectF &rectpos, QPixmap &outimg)
{
    int cx = static_cast<int>(circenterpoint.x());
    int cy = static_cast<int>(circenterpoint.y());
    int expandedRadius = mradius / mimagescale;
    float pointadd = 1.0;
    int pointTimer = 1;
    GetPointTimer(mradius, pointTimer, pointadd); // 取点倍数（360的倍数）

    // 计算截图的矩形位置（需要考虑窗口与图片的缩放比例，才能与画笔圆圈一致）
    int left = cx - expandedRadius;
    int top = cy - expandedRadius;
    int rectWidth = 2 * expandedRadius;
    int rectHeight = 2 * expandedRadius;

    // 返回的画笔图片位置
    rectpos.setX(cx - mradius);
    rectpos.setY(cy - mradius);
    rectpos.setWidth(mradius * 2); //
    rectpos.setHeight(mradius * 2);

    // 先绘制一个大小跟截图图片一致的pixmap，并绘制圆圈
    auto diameter = mradius * 2;
    QPixmap pixmap(diameter * mdevicpixratio, diameter * mdevicpixratio);
    pixmap.setDevicePixelRatio(mdevicpixratio);
    pixmap.fill(Qt::transparent); // 设置为透明背景
    QPainter painter(&pixmap);
    painter.setRenderHint(QPainter::Antialiasing, true); // 开启抗锯齿
    painter.save();
    painter.setPen(QPen(Qt::black, 1.0f));
    painter.setBrush(Qt::NoBrush);
    painter.drawEllipse(1, 1, diameter - 2, diameter - 2);
    painter.setPen(QPen(Qt::white, 1.0f));
    // 拷贝矩形区域形成新的QImage，并确定画笔位置的灰度亮度值，用于反色操作判断
    QImage v_outimg = sourceimg.copy(left, top, rectWidth, rectHeight);
    // v_outimg.save("outimg.png");
    auto alphaImage = v_outimg.convertToFormat(QImage::Format_Grayscale8); // 转换为灰度图

    // 画笔圆心在新QImage对象中的坐标
    QPointF newCenter(expandedRadius, expandedRadius);
    std::vector<QPointF> v_roundpoint;
    v_roundpoint.reserve(360 * pointTimer + 100);
    // 获取QImage上圆圈每个角度的点位信息合集共360个，用于判断每个角度点的灰度亮度值
    GetRoundPoints(newCenter, expandedRadius, pointadd, v_roundpoint);
    v_roundpoint.shrink_to_fit();

    // 确定pixmap圆圈矩形，用于绘制圆弧曲线
    QRectF roundrect;
    roundrect.setX(1);
    roundrect.setY(1);
    roundrect.setWidth(diameter - 2);
    roundrect.setHeight(diameter - 2);
    std::vector<double> posvec;
    posvec.reserve(360 * pointTimer + 100);
    posvec.clear();

    int times = 2;
    QPainterPath path;
    if (!v_roundpoint.empty())
    {
        if (!alphaImage.isNull())
        {
            double posindex = 0;
            int startAngle = 0; // 起始角度，16 分之一度单位
            int spanAngle = 0;  // 范围角度，16 分之一度单位
            bool antipos = false;
            for (auto i : v_roundpoint)
            {
                const uchar *line = alphaImage.scanLine(i.y());
                int x = i.x();
                uchar grayValue = line[x];
                if (grayValue < 125)
                {
                    if (!antipos)
                    {
                        antipos = true;
                        posvec.push_back(posindex);
                    }
                    else
                    {

                        if (posindex - posvec.back() <= 1 && (posindex - posvec.back()) > 0)
                        { // 可连在一起画
                            posvec.push_back(posindex);
                        }
                        else
                        {
                            if (posvec.size() > 1)
                            {
                                startAngle = (180 - posvec.front()) * 16;           // 起始角度，16 分之一度单位
                                spanAngle = -(posvec.back() - posvec.front()) * 16; // 范围角度，16 分之一度单位
                                painter.drawArc(roundrect, startAngle, spanAngle);  // 绘制圆弧
                                printf("内部连续绘制，起始角度=%lf,终止角度=%lf\n", posvec.front(), posvec.back());
                            }
                            posvec.clear();
                            posvec.push_back(posindex);
                        }
                    }
                }
                posindex += pointadd;
            }
            if (posvec.size() > 1)
            {
                startAngle = (180 - posvec.front()) * 16;           // 起始角度，16 分之一度单位
                spanAngle = -(posvec.back() - posvec.front()) * 16; // 范围角度，16 分之一度单位
                painter.drawArc(roundrect, startAngle, spanAngle);  // 绘制圆弧
                printf("外部连续绘制，起始角度=%lf,终止角度=%lf\n", posvec.front(), posvec.back());
            }
        }
        else
        {
            printf("alphaimage is null\n");
        }
    }
    printf("取点倍数=%d，点添加值=%lf\n", pointTimer, pointadd);
    outimg = pixmap;
    return ANTICIR_PEN_OK;
}

/**
 * 设置设备像素比
 * @param devpixratio
 */
void ColorAntiPen::setDevicepixratio(int devpixratio)
{
    mdevicpixratio = devpixratio;
}

/**
 * 设置设备半径
 * @param radius
 */
void ColorAntiPen::setRadius(int radius)
{
    mradius = radius;
}

/**
 * 设置图片窗口缩放比例
 * @param scale
 */
void ColorAntiPen::setImgWinScale(qreal scale)
{
    mimagescale = scale;
}

/**
 * 获取圆圈360个角度的位置
 * @param _centerpoint 圆心位置
 * @param _radius      半径
 * @param roundposvec  圆圈点位合集
 */
void ColorAntiPen::GetRoundPoints(QPointF _centerpoint, float _radius, float _pointadd, std::vector<QPointF> &roundposvec)
{
    std::list<QPoint> Firvec;
    std::list<QPoint> SecVec;
    std::list<QPoint> ThrVec;
    std::list<QPoint> FourVec;

    for (auto i = 0.0; i <= 90; i += _pointadd)
    {
        QPoint v_point;
        double radian = qDegreesToRadians(static_cast<double>(i));
        v_point.setX(_centerpoint.x() - (_radius - 1) * std::cos(radian));
        v_point.setY(_centerpoint.y() - (_radius - 1) * std::sin(radian));
        Firvec.emplace_back(v_point);
        if (i < 90)
        {
            v_point.setX(_centerpoint.x() + (_radius - 1) * std::cos(radian));
            v_point.setY(_centerpoint.y() - (_radius - 1) * std::sin(radian));
            SecVec.emplace_front(v_point);
        }
        if (i < 90)
        {
            v_point.setX(_centerpoint.x() + (_radius - 1) * std::cos(radian));
            v_point.setY(_centerpoint.y() + (_radius - 1) * std::sin(radian));
            ThrVec.emplace_back(v_point);
        }
        if (i < 90)
        {
            v_point.setX(_centerpoint.x() - (_radius - 1) * std::cos(radian));
            v_point.setY(_centerpoint.y() + (_radius - 1) * std::sin(radian));
            FourVec.emplace_front(v_point);
        }
    }
    roundposvec.insert(roundposvec.end(), Firvec.begin(), Firvec.end());
    roundposvec.insert(roundposvec.end(), SecVec.begin(), SecVec.end());
    roundposvec.insert(roundposvec.end(), ThrVec.begin(), ThrVec.end());
    roundposvec.insert(roundposvec.end(), FourVec.begin(), FourVec.end());
}

void ColorAntiPen::GetPointTimer(float _radius, int &_pointimer, float &_pointadd)
{
    if (_radius > 90 && _radius <= 180)
    {
        _pointimer = 2;
        _pointadd = 0.5;
    }
    else if (_radius > 180 && _radius <= 270)
    {
        _pointimer = 5;
        _pointadd = 0.2;
    }
    else if (_radius > 270)
    {
        _pointimer = 10;
        _pointadd = 0.1;
    }
}